﻿#include "MotionDlg.h"

#include <QGroupBox>
#include <QPushButton>
#include <QCheckBox>
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QRadioButton>
#include <QButtonGroup>
#include <qregularexpression>
#include <QRegularExpressionValidator>
#include <QListView>
#include <QFrame>
#include <QStringListModel>
#include <Qlistwidget>
#include <QTimer>
#include <QThread>
#include <QFile>
#include "DM2CMotion.h"

const int max_log_nums = 2000;	// 日志最大行数
const int interval_time = 200;	// 定时器间隔时间

MotionDlg::MotionDlg(QWidget* parent)
{
	initLayout();

	initMotion();

	//resize(400, 300);
	QTimer* timer = new QTimer(this);
	connect(timer, &QTimer::timeout, this, &MotionDlg::on_timeOut);
	timer->start(interval_time);
}

void MotionDlg::showEvent(QShowEvent* evnt)
{
	updateMacPosition();
}


void MotionDlg::initLayout()
{
	// 创建一个正则表达式，只允许输入数字
	QRegularExpression regExp("[0-9\.]+$");

	/***** 电机参数group box ******/
	QGroupBox* motionParamGroup = new QGroupBox("电机参数", this);
	QGridLayout* paramLayout = new QGridLayout();
	QLabel* vel = new QLabel("速度:");
	QLineEdit* velEdit = new QLineEdit();	
	// 创建一个正则表达式验证器
	auto val = new QRegularExpressionValidator(regExp, velEdit);	
	velEdit->setValidator(val);
	QLabel* acc = new QLabel("加速度:");
	QLineEdit* accEdit = new QLineEdit();
	QLabel* dec = new QLabel("减速度:");
	QLineEdit* decEdit = new QLineEdit();
	paramLayout->addWidget(vel, 0, 0, 1, 1);
	paramLayout->addWidget(velEdit, 0, 1, 1, 1);
	paramLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 2, 1, 1);
	paramLayout->addWidget(acc, 1, 0, 1, 1);
	paramLayout->addWidget(accEdit, 1, 1, 1, 1);
	paramLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 2, 1, 1);
	paramLayout->addWidget(dec, 2, 0, 1, 1);
	paramLayout->addWidget(decEdit, 2, 1, 1, 1);
	paramLayout->addItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 2, 1, 1);
	QPushButton* setBtn = new QPushButton("设置参数");
	paramLayout->addWidget(setBtn, 3, 0, 1, 1);

	vel_ = velEdit;
	acc_ = accEdit;
	dec_ = decEdit;
	

	motionParamGroup->setLayout(paramLayout);



	/***** 运动方式 ******/
	QGroupBox* motionGroup = new QGroupBox("电机运动");
	QGridLayout* motionLayout = new QGridLayout();

	QLabel* labelCmdPos = new QLabel("命令位置:");
	QLineEdit* cmdPosEdit = new QLineEdit();
	labelCmdPos->setBuddy(cmdPosEdit);
	cmdPosEdit->setEnabled(false);
	QLabel* labelMacPos = new QLabel("电机位置:");
	QLineEdit* macPosEdit = new QLineEdit();
	labelMacPos->setBuddy(macPosEdit);
	macPosEdit->setEnabled(false);
	cmdPos_ = cmdPosEdit;
	macPos_ = macPosEdit;
	int row = 0;
	motionLayout->addWidget(labelCmdPos, row, 0, 1, 1);
	motionLayout->addWidget(cmdPosEdit, row, 1, 1, 1);
	row++;
	motionLayout->addWidget(labelMacPos, row, 0, 1, 1);
	motionLayout->addWidget(macPosEdit, row, 1, 1, 1);
	//motionLayout->addItem(new QSpacerItem(10,0,QSizePolicy::Expanding, QSizePolicy::Minimum), row, 4,1,1);
	row++;

	// 添加分割线
	QFrame* line1 = new QFrame();
	line1->setFrameShape(QFrame::HLine);
	line1->setFrameShadow(QFrame::Sunken);
	motionLayout->addWidget(line1, row, 0, 1, 4);
	row++;

	// 相对运动
	QLabel* stepMove = new QLabel("相对坐标");
	QLabel* stepLen = new QLabel("步长：");
	QLineEdit* stepLenEdit = new QLineEdit();
	QPushButton* forwardBtn = new QPushButton("正向移动");
	QPushButton* backBtn = new QPushButton("反向移动");
	// 绝对坐标
	QLabel* coordMove = new QLabel("绝对坐标");
	QPushButton* moveTo = new QPushButton("移动到：");
	QLineEdit* coordEdit = new QLineEdit();
	// 急停按钮
	QPushButton* stopBtn = new QPushButton("停止");
	//stopBtn->setGeometry(0, 0, 100, 100);
	//stopBtn->setBaseSize(100, 100);

	stepLength_ = stepLenEdit;
	destCoord_ = coordEdit;

	allBtns_.push_back(forwardBtn);
	allBtns_.push_back(backBtn);

	motionLayout->addWidget(stepMove, row, 0, 1, 1);
	row++;
	motionLayout->addWidget(stepLen, row, 0, 1, 1);
	motionLayout->addWidget(stepLenEdit, row, 1, 1, 1);
	row++;
	motionLayout->addWidget(forwardBtn, row, 0, 1, 1);
	motionLayout->addWidget(backBtn, row, 1, 1, 1);
	row++;

	// 插入分割线
	QFrame* line2 = new QFrame();
	line2->setFrameShape(QFrame::HLine);
	line2->setFrameShadow(QFrame::Sunken);
	motionLayout->addWidget(line2, row, 0, 1, 4);
	row++;

	motionLayout->addWidget(coordMove, row, 0, 1, 1);
	row++;
	motionLayout->addWidget(moveTo, row, 0, 1, 1);
	motionLayout->addWidget(coordEdit, row, 1, 1, 1);
	row++;
	// 插入分割线
	QFrame* line3 = new QFrame();
	line3->setFrameShape(QFrame::HLine);
	line3->setFrameShadow(QFrame::Sunken);
	motionLayout->addWidget(line3, row, 0, 1, 4);
	row++;
	motionLayout->addWidget(stopBtn, row, 1, 1, 2);

	motionGroup->setLayout(motionLayout);

	// 初始化
	velEdit->setText(QString::number(300));
	accEdit->setText(QString::number(50));
	decEdit->setText(QString::number(50));
	stepLenEdit->setText(QString::number(20000));
	coordEdit->setText(QString::number(20000));

	/***** 回零操作 group box ******/
	QGroupBox* homeGroup = new QGroupBox("回零操作", this);
	QGridLayout* homeGridLayout = new QGridLayout();
	// 回零模式
	QLabel* homeMode = new QLabel("回原点模式:");
	QRadioButton* limitHome = new QRadioButton("限位回零");
	QRadioButton* origHome = new QRadioButton("原点回零");
	homeModeGroup_ = new QButtonGroup(this);
	homeModeGroup_->addButton(limitHome, 0);
	homeModeGroup_->addButton(origHome, 1);
	limitHome->setChecked(true);
	// 回零方向
	QLabel* homeDir = new QLabel("回零方向:");
	QRadioButton* posiHome = new QRadioButton("正向回零");
	QRadioButton* negHome = new QRadioButton("反向回零");
	moveDirGroup_ = new QButtonGroup(this);
	moveDirGroup_->addButton(negHome, 0);
	moveDirGroup_->addButton(posiHome, 1);
	negHome->setChecked(true);
	// button
	QPushButton* homeBtn = new QPushButton("回原点");
	QPushButton* setAsZeroBtn = new QPushButton("设为零点");
	homeGridLayout->addWidget(homeMode, 0, 0, 1, 1);
	homeGridLayout->addWidget(limitHome, 0, 1, 1, 1);
	homeGridLayout->addWidget(origHome, 0, 2, 1, 1);
	homeGridLayout->addWidget(homeDir, 1, 0, 1, 1);
	homeGridLayout->addWidget(negHome, 1, 1, 1, 1);
	homeGridLayout->addWidget(posiHome, 1, 2, 1, 1);
	homeGridLayout->addWidget(homeBtn, 2, 0, 1, 1);
	homeGridLayout->addWidget(setAsZeroBtn, 2, 1, 1, 1);
	homeGroup->setLayout(homeGridLayout);

	allBtns_.push_back(homeBtn);
	allBtns_.push_back(setAsZeroBtn);


	/***** IO操作group box ******/
	QGroupBox* ioGroup = new QGroupBox("IO测试", this);
	QGridLayout* ioGridLayout = new QGridLayout();
	// 三色灯
	QRadioButton* redBee = new QRadioButton("红灯+蜂鸣");
	QRadioButton* yellow = new QRadioButton("黄灯");
	QRadioButton* green = new QRadioButton("绿灯");

	ioSelectGroup_ = new QButtonGroup();
	ioSelectGroup_->addButton(redBee, 0);
	ioSelectGroup_->addButton(yellow, 1);
	ioSelectGroup_->addButton(green, 2);

	// button
	QPushButton* closeIO = new QPushButton("清空IO输出");
	QCheckBox* checkCloseAlarm = new QCheckBox("关闭报警");
	ioGridLayout->addWidget(redBee, 0, 0, 1, 1);
	ioGridLayout->addWidget(yellow, 0, 1, 1, 1);
	ioGridLayout->addWidget(green, 0, 2, 1, 1);
	ioGridLayout->addWidget(closeIO, 1, 0, 1, 1);
	ioGridLayout->addWidget(checkCloseAlarm, 1, 2, 1, 2);
	ioGroup->setLayout(ioGridLayout);
	allBtns_.push_back(closeIO);

	listLog_ = new QListWidget(this);
	listLog_->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding);
	listLog_->setMinimumWidth(400);
	listLog_->setStyleSheet("QListWidget {background-color:white;}");
	QPushButton* clearBtn = new QPushButton("清除", this);
	QVBoxLayout* vBoxR = new QVBoxLayout();
	vBoxR->addWidget(listLog_);
	vBoxR->addWidget(clearBtn);

	QVBoxLayout* vBoxL = new QVBoxLayout();
	vBoxL->addWidget(motionParamGroup);
	vBoxL->addWidget(motionGroup);
	vBoxL->addWidget(homeGroup);
	vBoxL->addWidget(ioGroup);


	QHBoxLayout* mainLayout = new QHBoxLayout(this);
	mainLayout->addLayout(vBoxL);
	mainLayout->addLayout(vBoxR);

	setLayout(mainLayout);

	connect(setBtn, SIGNAL(clicked(bool)), this, SLOT(on_setRunParams()));
	connect(limitHome, SIGNAL(clicked(bool)), this, SLOT(on_radioHomeMode()));
	connect(origHome, SIGNAL(clicked(bool)), this, SLOT(on_radioHomeMode()));

	connect(posiHome, SIGNAL(clicked(bool)), this, SLOT(on_radioMoveDir()));
	connect(negHome, SIGNAL(clicked(bool)), this, SLOT(on_radioMoveDir()));

	connect(redBee, SIGNAL(clicked(bool)), this, SLOT(on_radioIOSel()));
	connect(yellow, SIGNAL(clicked(bool)), this, SLOT(on_radioIOSel()));
	connect(green, SIGNAL(clicked(bool)), this, SLOT(on_radioIOSel()));
	connect(closeIO, SIGNAL(clicked(bool)), this, SLOT(on_resetAllIO()));

	connect(clearBtn, SIGNAL(clicked(bool)), this, SLOT(on_clearLogs()));

	connect(forwardBtn, SIGNAL(clicked(bool)), this, SLOT(on_moveForward()));
	connect(backBtn, SIGNAL(clicked(bool)), this, SLOT(on_moveBack()));
	connect(moveTo, SIGNAL(clicked(bool)), this, SLOT(on_moveTo()));
	connect(homeBtn, SIGNAL(clicked(bool)), this, SLOT(on_home()));
	connect(setAsZeroBtn, SIGNAL(clicked(bool)), this, SLOT(on_setAsOriginal()));

	connect(stopBtn, SIGNAL(clicked(bool)), this, SLOT(on_stopMove()));


	writeLog("send information");
	receiveLog("receive information");
}

void MotionDlg::initMotion()
{
	dmcMotion_ = DM2CMotion::instance();
}

void MotionDlg::on_setRunParams()
{
	int vel = vel_->text().toInt();
	int acc = acc_->text().toInt();
	int dec = dec_->text().toInt();
	writeLog(std::string("设置运动参数: " + std::to_string(vel) + "," + std::to_string(acc) + "," + std::to_string(dec)).c_str());
	dmcMotion_->setParams(vel, acc, dec);
}


void MotionDlg::on_moveForward()
{
	int len = stepLength_->text().toInt();
	writeLog(std::string("正向移动：" + std::to_string(len)).c_str());

	setRunning(true);
	enableBtns(false);
	dmcMotion_->move(len);
	
	QThread::msleep(10);
}

void MotionDlg::on_moveBack()
{
	int len = stepLength_->text().toInt();
	writeLog(std::string("反向移动：" + std::to_string(len)).c_str());

	setRunning(true);
	enableBtns(false);
	dmcMotion_->move(-len);

	QThread::msleep(10);
}

void MotionDlg::on_moveTo()
{
	int destPos = destCoord_->text().toInt();
	writeLog(std::string("移动到：" + std::to_string(destPos)).c_str());

	setRunning(true);
	enableBtns(false);
	
	int vel = vel_->text().toInt();
	int acc = acc_->text().toInt();
	int dec = dec_->text().toInt();
	dmcMotion_->moveTo(destPos, vel, acc, dec);

	QThread::msleep(10);
}

void MotionDlg::on_stopMove()
{
	writeLog("紧急停止");

	enableBtns(true);
	dmcMotion_->eStop();
	setRunning(false);
	QThread::msleep(10);

	// 返回当前坐标
	updateMacPosition();
}

void MotionDlg::on_home()
{
	writeLog("电机开始回原点.");
	setRunning(true);
	enableBtns(false);
	dmcMotion_->home(moveDir_, homeMode_);
}

void MotionDlg::on_setAsOriginal()
{
	writeLog("当前位置设为零位");
	dmcMotion_->setAsOrig();
}

void MotionDlg::on_resetAllIO()
{
	writeLog("关闭当前所有IO输出");
	dmcMotion_->writeGreen(false);
	dmcMotion_->writeYellow(false);
	dmcMotion_->writeRedAndBuzzer(false);
}

void MotionDlg::on_clearLogs()
{
	listLog_->clear();
}

void MotionDlg::on_radioHomeMode()
{
	int id = homeModeGroup_->checkedId();
	homeMode_ = id;
}

void MotionDlg::on_radioMoveDir()
{
	int id = moveDirGroup_->checkedId();
	moveDir_ = id;
}

void MotionDlg::on_radioIOSel()
{
	dmcMotion_->writeRedAndBuzzer(false);
	dmcMotion_->writeYellow(false);
	dmcMotion_->writeGreen(false); 
	switch (ioSelectGroup_->checkedId())
	{
	case 0:
		dmcMotion_->writeRedAndBuzzer(true);
		break;
	case 1:
		dmcMotion_->writeYellow(true);
		break;
	case 2:
		dmcMotion_->writeGreen(true);
		break;
	}
}

#include <iostream>
#include <sstream>
// 整数转16进制字符串
std::string intToHexString(int number) {
	std::stringstream ss;
	ss << std::hex << number;
	return ss.str();
}

// 设备状态码：0x1003
// 代码 运行状态
// Bit0 故障
// Bit1 使能
// Bit2 运行
// Bit4 指令完成
// Bit5 路径完成
// Bit6 回零完成

// 运行状态码：0x6002
// 通过对 0x6002 写入相应的命令实现各动作的选择和启动。
// 往地址 0x6002 写 0x01P(P 为路径号 0~15)，P 段定位；
// 往地址 0x6002 写 0x020，回零；
// 往地址 0x6002 写 0x021，当前位置手动设零；
// 往地址 0x6002 写 0x040，急停；
// 读地址 0x6002，显示值为 0x000p(P 为路径号 0~15)，表示定位完成，可接收新数据；
// 读地址 0x6002，显示值为 0x01P(P 为路径号 0~15)、0x020、0x040 表示还未响应命令；
// 读地址 0x6002，显示值为 0x10P(P 为路径号 0~15) ，表示路径运行中；
// 读地址 0x6002，显示值为 0x200，表示指令完成等待定位。


void MotionDlg::on_timeOut()
{
	if (!isRunning())
	{
		return;
	}

	//uint16_t runState = dmcMotion_->getRunState();
	bool complete = true;
	
	/*uint16_t hBits = 0xFF00 & runState;
	uint16_t lBits = 0x00FF & runState;
	std::string info = "未知状态";
	switch (hBits)
	{
	case 0x0000:
		if (lBits < 16)
		{
			info = "返回码:" + intToHexString(runState) + " - 路径完成定位";
		}
		else
		{
			info = "返回码:" + intToHexString(runState) + " - 未响应指令";
		}
		receiveLog(info.c_str());
		break;
	case 0x0100:
		info = "返回码:" + intToHexString(runState) + " - 路径运行中";
		complete = false;
		break;
	case 0x0200:
		info = "返回码:" + intToHexString(runState) + " - 指令完成等待定位";
		receiveLog(info.c_str());
		break;
	default:
		info = "返回码:" + intToHexString(runState) + " - 未知状态";
		receiveLog(info.c_str());
		break;
	}*/
	
	uint16_t runState = dmcMotion_->getMacState();
	/*int state = runState & 0x0001;
	if (state == 0x0001)
	{
		receiveLog("设备故障");
	}
	if ((runState & 0x0002) == 0)
	{
		receiveLog("设备未使能状态");
	}
	if ((runState & 0x0004) > 0)
	{
		receiveLog("运行状态");
	}
	if ((runState & 0x0010) > 0)
	{
		receiveLog("指令完成");
	}
	if ((runState & 0x0020) > 0)
	{
		receiveLog("路径完成");
	}
	if ((runState & 0x0040) > 0)
	{
		receiveLog("回零完成");
	}
	if (runState == 0x32)
	{
		receiveLog("指令路径完成");
	}*/

	switch (runState)
	{
	case 0x00:
		receiveLog("状态获取失败: 0x00");
		break;
	case 0x01:
		receiveLog("设备故障：0x01");
		break;
	case 0x06:
		//WriteLog("<<< 运行状态: 0x06");
		complete = false;
		break;
	case 0x32:	// 0x32=50
		receiveLog("路径完成: 0x32");
		break;
	case 0x46:	// 0100 0110
	case 0x72:	// 0x72=114
		receiveLog(std::string("回零完成: " + intToHexString(runState)).c_str());
		break;
	case 0x52:	// 回零操作
		receiveLog("回零完成: 0x52");
		break;
	default:
		receiveLog(std::string("未知状态." + intToHexString(runState)).c_str());
		break;
	}

	if (complete)
	{
		setRunning(false);
		enableBtns(true);

		// 刷新当前的坐标
		updateMacPosition();
	}
}

void MotionDlg::updateMacPosition()
{
	int cmdPos = 0;
	int macPos = 0;
	dmcMotion_->currentPos(&cmdPos, &macPos);

	cmdPos_->setText(QString::number(cmdPos));
	macPos_->setText(QString::number(macPos));
}

void MotionDlg::writeLog(const char* data)
{
	int count = listLog_->count();
	if (count >= max_log_nums)
	{
		listLog_->takeItem(0);
	}
	listLog_->addItem(QString(">>> ") + QString(data));
	listLog_->scrollToBottom();
}

void MotionDlg::receiveLog(const char* data)
{
	int count = listLog_->count();
	if (count >= max_log_nums)
	{
		listLog_->takeItem(0);
	}
	listLog_->addItem(QString("<<< ") + QString(data));
	listLog_->scrollToBottom();
}

void MotionDlg::enableBtns(bool enable)
{
	for (auto& p : allBtns_)
	{
		p->setEnabled(enable);
	}
}
